﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Text;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using CNative.Utilities;

namespace CNative.Dapper.Utils
{
    #region InsertSqlBuilder
    internal class InsertSqlBuilder : BaseSqlBuilder, IInsertSqlBuilder
    {
        public InsertSqlBuilder(IDbHelper _db) : base(_db)
        {
        }

        #region Insert
        /// <summary>
        /// 插入实体表达式
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="values"></param>
        /// <returns></returns>
        public IInsertSqlBuilder Insert<TClass>(Expression<Func<TClass, TClass>> values) where TClass : class, new()
        {
            if (values.IsNotNullOrEmpty())
            {
                var sql = BuildInsert(values);
                if (sql != null)
                    sqlList.Add(sql);
            }
            return this;
        }
        /// <summary>
        /// 插入实体
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public IInsertSqlBuilder Insert<TClass>(TClass entity) where TClass : class, new()
        {
            if (entity.IsNotNullOrEmpty())
            {
                var tableInfo = GetTableInfo<TClass>();
                var sql = BuildInsert(entity, tableInfo, false);
                if (sql != null)
                    sqlList.Add(sql);
            }
            return this;
            //return Insert(new List<TClass> { entity });
        }
        /// <summary>
        /// 插入实体集合
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Insert<TClass>(List<TClass> entities) where TClass : class, new()
        {
            if (!entities.IsNullOrEmpty_())
            {
                if (entities.Count > 50)//超50条自动用批量导入方式
                    return BulkCopyData(entities);

                var tableInfo = GetTableInfo<TClass>();
                //通过实体设置字段
                var dicfields = BuildFields(entities[0], (f) => f.PropertyInfo != null && f.Type.IsNotNullOrEmpty() && f.IsIdentity == false, tableInfo);
                if (dicfields.IsNullOrEmpty_()) return false;
                var sqle = CreateSqlEntity();
                //生成脚本
                if (BuildInsertSQL(sqle, dicfields, tableInfo, false, ""))
                {
                    if (entities.Count > 1)
                    {
                        sqle.Parameters = null;
                        sqle.Parameter = entities;
                    }
                    sqlList.Add(sqle);
                }
                //entities.ForEach(entity =>
                //{
                //    if (entity.IsNotNullOrEmpty())
                //    {
                //        var sql = BuildInsert(entity, tableInfo, false);
                //        if (sql != null)
                //            sqlList.Add(sql);
                //    }
                //});
            }
            return this.Exec;
        }
        #endregion
        #region InsertSelect
        /// <summary>
        /// 从一个表复制数据，然后把数据插入到一个已存在的表中
        /// INSERT INTO SELECT 语句
        /// <typeparam name="TINTO">INSERT INTO目标表</typeparam>
        /// <typeparam name="TSELECT">SELECT数据源表</typeparam>
        /// <param name="values"></param>
        /// <returns></returns>
        public IInsertSqlBuilder InsertSelect<TINTO, TSELECT>(Expression<Func<TSELECT, TINTO>> values, Expression<Func<TSELECT, bool>> where) where TINTO : class, new() where TSELECT : class, new()
        {
            var tableInto = GetTableInfo<TINTO>();
            var tbInto = tableInto.Item1;
            if (tbInto == null) return null;

            var tableSelect = GetTableInfo<TSELECT>();
            var tbSelect = tableSelect.Item1;
            if (tbSelect == null) return null;
            //通过实体设置字段
            var dicfields = BuildFields(values, (f) => f.PropertyInfo == null || f.IsIdentity == true);
            //---------------------------------------------------------------------------------------------------------------
            var sqle = CreateSqlEntity();
            var whereStr = BuildWhereExp(sqle, where, null);
            if (whereStr.IsNullOrEmpty())
            {
                whereStr = "1=1";
            }
            //else
            //{
            //    whereStr = whereStr.ReplaceIgnoreCase("WHERE", "").TrimPrefixName("AND").TrimPrefixName("OR");
            //}
            //---------------------------------------------------------------------------------------------------------------
            var sqlMeta = db.SqlDbProvider.GetInsertSelectSql(tableInto.Item3, tableSelect.Item3);
            string sqlIntofield = "", sqlSelectfield = "";
            dicfields.ForEach(dic =>
            {
                sqlIntofield += "," + suffixLeft + dic.Key + suffixRigh;
                //------------------------------------------------------------------
                if (dic.Value.Item2 is System.Reflection.MemberInfo mb)
                {
                    sqlSelectfield += "," + mb.GetColumnName();
                }
                else
                {
                    if (AddDbParameter(dic.Key, dic.Value.Item2, sqle, out string paraName, "selp_", tupleTableInfo?.Item1))
                    {
                        sqlSelectfield += "," + paraName + " as " + dic.Key;
                    }
                }
            });
            sqlIntofield = sqlIntofield.Trim(',');
            sqlSelectfield = sqlSelectfield.Trim(',');

            sqle.Sql = string.Format(sqlMeta, sqlIntofield, sqlSelectfield, whereStr);

            sqlList.Add(sqle);

            return this;
        }
        #endregion
        //---------------------------------------------------------------------------------------------------------------
        #region InsertOrUpdate
        /// <summary>
        /// 保存数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <typeparam name="TClass">实体类型</typeparam>
        /// <param name="entity">实体对象</param>
        /// <param name="where">条件表达式</param>
        /// <param name="columns">需要更新的字段</param>
        public bool InsertOrUpdate<TClass>(TClass entity, Expression<Func<TClass, bool>> where, params string[] columns) where TClass : class, new()
        {
            var whereStr = BuildWhereExp(sqlent, where, null);
            if (whereStr.IsNullOrEmpty())
            {
                return false;
            }
            sqlent.Sql = whereStr;
            return UpdateOrInsertBase(new List<TClass> { entity }, sqlent, false, columns);
        }

        /// <summary>
        /// 保存数据多条数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <typeparam name="TClass">实体类型</typeparam>
        /// <param name="entities">数据列表</param>
        /// <param name="columns">需要更新的字段</param>
        public bool InsertOrUpdate<TClass>(List<TClass> entities, params string[] columns) where TClass : class, new()
        {
            sqlent.Parameters = null;
            sqlent.Sql = "";
            return UpdateOrInsertBase(entities, sqlent, true, columns);
        }

        /// <summary>
        /// 保存数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <typeparam name="TClass">实体类型</typeparam>
        /// <param name="entity">实体对象</param>
        /// <param name="where">条件表达式</param>
        /// <param name="IgnoreColumns">不需要更新的字段</param>
        public bool InsertOrUpdate<TClass>(TClass entity, Expression<Func<TClass, bool>> where, IEnumerable<string> IgnoreColumns) where TClass : class, new()
        {
            var whereStr = BuildWhereExp(sqlent, where, null);
            if (whereStr.IsNullOrEmpty())
            {
                return false;
            }
            sqlent.Sql = whereStr;
            return UpdateOrInsertBase(new List<TClass> { entity }, sqlent, false, IgnoreColumns);
        }
        /// <summary>
        /// 保存数据多条数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <typeparam name="TClass">实体类型</typeparam>
        /// <param name="entities">数据列表</param>
        /// <param name="where">条件表达式</param>
        /// <param name="IgnoreColumns">不需要更新的字段</param>
        public bool InsertOrUpdate<TClass>(List<TClass> entities, IEnumerable<string> IgnoreColumns = null) where TClass : class, new()
        {
            sqlent.Parameters = null;
            sqlent.Sql = "";
            return UpdateOrInsertBase(entities, sqlent, false, IgnoreColumns);
        }


        /// <summary>
        /// 保存数据（自动新增或更新动作）
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="fields">设置多个更新字段</param>
        /// <param name="where">条件表达式</param>
        /// <returns></returns>
        public bool InsertOrUpdate<TClass>(Expression<Func<TClass, TClass>> fields, Expression<Func<TClass, bool>> where) where TClass : class, new()
        {
            var tableInfo = GetTableInfo<TClass>();
            return UpdateOrInsertBase(fields, where, tableInfo);
        }
        #endregion
        //-------------------------------------------------------------------------------------------------------------------------------
        #region Exists
        /// <summary>
        /// 通过主键，判断实体是否存在表中
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public bool Exists<TClass>(TClass entity) where TClass : class, new()
        {
            return base.Exists(entity);
        }
        /// <summary>
        /// 通过主键，判断实体是否存在表中
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public bool Exists<TClass>(Expression<Func<TClass, bool>> where) where TClass : class, new()
        {
            return base.Exists(where);
        }
        #endregion
        //-------------------------------------------------------------------------------------------------------------------------------
        #region override

        protected override bool Build(bool isCount = false)
        {
            isBuilded = true;
            return true;
        }
        #endregion

    }
    #endregion
    #region InsertSqlBuilder<TClass>
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TClass">实体类型</typeparam>
    internal class InsertSqlBuilder<TClass> : InsertSqlBuilder, IInsertSqlBuilder<TClass> where TClass : class, new()
    {
        public InsertSqlBuilder(IDbHelper _db) : base(_db)
        {
            From();
        }

        #region Insert
        /// <summary>
        /// 插入实体表达式
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="values"></param>
        /// <returns></returns>
        public IInsertSqlBuilder<TClass> Insert(Expression<Func<TClass,TClass>> values) 
        {
            base.Insert(values);
            return this;
        }
        /// <summary>
        /// 插入实体
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public IInsertSqlBuilder<TClass> Insert(TClass entity)
        {
            base.Insert(entity);
            return this;
        }
        /// <summary>
        /// 插入实体集合
        /// </summary>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Insert(List<TClass> entities)
        {
            return base.Insert(entities);
        }
        /// <summary>  
        /// 批量插入功能  
        /// </summary>  
        public bool BulkCopyData(List<TClass> entityList, int? bulkCopyTimeout = null)
        {
            return base.BulkCopyData(entityList, bulkCopyTimeout);
        }
        #endregion
        #region InsertSelect
        /// <summary>
        /// 从一个表复制数据，然后把数据插入到一个已存在的表中
        /// INSERT INTO SELECT 语句
        /// <typeparam name="TINTO">INSERT INTO目标表</typeparam>
        /// <typeparam name="TSELECT">SELECT数据源表</typeparam>
        /// <param name="values"></param>
        /// <returns></returns>
        public IInsertSqlBuilder<TClass> InsertSelect<TSELECT>(Expression<Func<TSELECT, TClass>> values, Expression<Func<TSELECT, bool>> where) where TSELECT : class, new()
        {
            base.InsertSelect(values, where);
            return this;
        }
        #endregion
        //---------------------------------------------------------------------------------------------------------------
        #region InsertOrUpdate
        /// <summary>
        /// 保存数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="where">条件表达式</param>
        /// <param name="columns">需要更新的字段</param>
        public bool InsertOrUpdate(TClass entity, Expression<Func<TClass, bool>> where, params string[] columns)
        {
            return base.InsertOrUpdate(entity, where, columns);
        }

        /// <summary>
        /// 保存数据多条数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <param name="entities">数据列表</param>
        /// <param name="columns">需要更新的字段</param>
        public bool InsertOrUpdate(List<TClass> entities, params string[] columns) 
        {
            return base.InsertOrUpdate(entities, columns);
        }

        /// <summary>
        /// 保存数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="where">条件表达式</param>
        /// <param name="IgnoreColumns">不需要更新的字段</param>
        public bool InsertOrUpdate(TClass entity, Expression<Func<TClass, bool>> where, IEnumerable<string> IgnoreColumns)
        {
            return base.InsertOrUpdate(entity, where, IgnoreColumns);
        }
        /// <summary>
        /// 保存数据多条数据（自动新增或更新动作）,某些属性,默认更新实体列表，所有字段
        /// </summary>
        /// <param name="entities">数据列表</param>
        /// <param name="where">条件表达式</param>
        /// <param name="IgnoreColumns">不需要更新的字段</param>
        public bool InsertOrUpdate(List<TClass> entities, IEnumerable<string> IgnoreColumns = null)
        {
            return base.InsertOrUpdate(entities, IgnoreColumns);
        }


        /// <summary>
        /// 保存数据（自动新增或更新动作）
        /// </summary>
        /// <param name="fields">设置多个更新字段</param>
        /// <param name="where">条件表达式</param>
        /// <returns></returns>
        public bool InsertOrUpdate(Expression<Func<TClass,TClass>> fields, Expression<Func<TClass, bool>> where)
        {
            return base.InsertOrUpdate(fields, where);
        }
        #endregion
        //-------------------------------------------------------------------------------------------------------------------------------
        #region Exists
        /// <summary>
        /// 通过主键，判断实体是否存在表中
        /// </summary>
        /// <returns></returns>
        public bool Exists(TClass entity)
        {
            return base.Exists(entity);
        }
        /// <summary>
        /// 通过主键，判断实体是否存在表中
        /// </summary>
        /// <returns></returns>
        public bool Exists(Expression<Func<TClass, bool>> where)
        {
            return base.Exists(where);
        }
        #endregion

        /// <summary>
        /// 开始
        /// </summary>
        /// <returns></returns>
        protected virtual Tuple<DbTableInfo, string, string> From()
        {
            tupleTableInfo = GetTableInfo<TClass>();
            fromStr = $"{tupleTableInfo.Item3}";
            return tupleTableInfo;
        }
    }
    #endregion
}
